package cn.com.guage.transtation.threephasecommit.demo;

class Account {
    private String name;
    private int balance;
    private int tempBalance;

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
        this.tempBalance = balance;
    }

    public String getName() {
        return name;
    }

    public boolean canCommit(int amount) {
        return (balance + amount) >= 0;
    }

    public void preCommit(int amount) {
        tempBalance = balance + amount;
    }

    public void doCommit() {
        balance = tempBalance;
    }

    public void abort() {
        tempBalance = balance;
    }

    public int getBalance() {
        return balance;
    }

    public int getTempBalance() {
        return tempBalance;
    }
}

class Coordinator {
    private Account zhangsanAccount;
    private Account lisiAccount;
    private boolean canCommitSuccess = false;
    private boolean preCommitSuccess = false;

    public Coordinator(Account zhangsanAccount, Account lisiAccount) {
        this.zhangsanAccount = zhangsanAccount;
        this.lisiAccount = lisiAccount;
    }

    public boolean canCommitPhase(int amount) {
        boolean zhangsanCanCommit = zhangsanAccount.canCommit(-amount);
        boolean lisiCanCommit = lisiAccount.canCommit(amount);
        canCommitSuccess = zhangsanCanCommit && lisiCanCommit;
        return canCommitSuccess;
    }

    public boolean preCommitPhase(int amount) {
        if (!canCommitSuccess) return false;
        zhangsanAccount.preCommit(-amount);
        lisiAccount.preCommit(amount);
        preCommitSuccess = true;
        return true;
    }

    public boolean doCommitPhase() {
        if (!preCommitSuccess) return false;
        zhangsanAccount.doCommit();
        lisiAccount.doCommit();
        return true;
    }

    public void abort() {
        zhangsanAccount.abort();
        lisiAccount.abort();
    }
}

public class ThreePCBankTransfer {
    public static void main(String[] args) {
        Account zhangSan = new Account("张三", 1000);
        Account liSi = new Account("李四", 1000);
        Coordinator coordinator = new Coordinator(zhangSan, liSi);
        int transferAmount = 500;

        System.out.println("初始状态:");
        printBalances(zhangSan, liSi);

        // CanCommit 阶段
        System.out.println("\n--- CanCommit 阶段 ---");
        if (coordinator.canCommitPhase(transferAmount)) {
            System.out.println("所有参与者同意提交，进入PreCommit阶段。");
        } else {
            System.out.println("CanCommit阶段失败，事务中止。");
            coordinator.abort();
        }
        printBalances(zhangSan, liSi);

        // PreCommit 阶段
        System.out.println("\n--- PreCommit 阶段 ---");
        if (coordinator.preCommitPhase(transferAmount)) {
            System.out.println("预提交成功，临时余额已计算（未生效）。");
            System.out.println("张三临时余额: " + zhangSan.getTempBalance());
            System.out.println("李四临时余额: " + liSi.getTempBalance());
        } else {
            System.out.println("PreCommit阶段失败，事务中止。");
            coordinator.abort();
        }
        printBalances(zhangSan, liSi);

        // DoCommit 阶段
        System.out.println("\n--- DoCommit 阶段 ---");
        if (coordinator.doCommitPhase()) {
            System.out.println("事务提交成功，资金已转移。");
        } else {
            System.out.println("DoCommit阶段失败，事务回滚。");
            coordinator.abort();
        }
        printBalances(zhangSan, liSi);
    }

    private static void printBalances(Account a1, Account a2) {
        System.out.println("当前账户余额:");
        System.out.println(a1.getName() + ": " + a1.getBalance());
        System.out.println(a2.getName() + ": " + a2.getBalance());
    }
}